package labox.innovation.loginserver.socket;

import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.security.interfaces.RSAPrivateKey;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import labox.innovation.config.Config;
import labox.innovation.gameserver.network.BlowFishKeygen;
import labox.innovation.gameserver.network.GameCrypt;
import labox.innovation.loginserver.Client;
import labox.innovation.loginserver.LoginController;
import labox.innovation.loginserver.SessionKey;
import labox.innovation.loginserver.socket.serverpackets.LoginServerPacket;
import labox.innovation.loginserver.socket.serverpackets.LoginFail;
import labox.innovation.loginserver.socket.serverpackets.LoginFail.LoginFailReason;
import labox.innovation.util.Rnd;
import labox.innovation.util.Util;
import labox.innovation.util.crypt.BlowFishKeygenForLogin;
import labox.innovation.util.crypt.LoginCrypt;
import labox.innovation.util.crypt.ScrambledKeyPair;

import labox.innovation.netcore.MMOClient;
import labox.innovation.netcore.MMOConnection;

/**
 * Represents a client connected into the LoginServer
 * 
 * @author KenM
 */
public final class LoginClient extends MMOClient<MMOConnection<LoginClient>> implements Client {

	private static final Logger _log = LoggerFactory.getLogger(LoginClient.class.getName());

	//-- 枚举玩家登陆状态
	public static enum LoginClientState {
		/**
		 * 连接
		 */
		CONNECTED,

		/**
		 * 授权
		 */
		AUTHED_GG,

		/**
		 * 登陆
		 */
		AUTHED_LOGIN
	};

	private LoginClientState _state;

	private String _account;

	private int _accessLevel;

	private int _lastServer;

	private boolean _usesInternalIP;

	private int _sessionKey;

	private int _sessionId;

	private long _connectionStartTime;
	
	private LoginCrypt _loginCrypt;
	
	private String _channelId;

	/**
	 * 构造一个player的客户端对象
	 * 
	 * @param con
	 */
	public LoginClient(MMOConnection<LoginClient> con) {
		super(con);
		_state = LoginClientState.CONNECTED;//客户端最初的状态是CONNECTED
		String ip = getConnection().getInetAddress().getHostAddress();

		if (Util.isInternalIP(ip) && !Config.ROUTER_HOSTNAME.equalsIgnoreCase(ip)) {
			_usesInternalIP = true;
		}
		_loginCrypt = new LoginCrypt();
		_sessionId = Rnd.nextInt(); //-- 随机产生seesionId
		_connectionStartTime = System.currentTimeMillis();
	}

	public boolean usesInternalIP() {
		return _usesInternalIP;
	}
	
	public byte[] enableCrypt() {
		byte[] key = BlowFishKeygenForLogin.getRandomKey();
		_loginCrypt.setKey(key);
		return key;
	}

	/**
	 * @see com.l2jserver.mmocore.interfaces.MMOClient#decrypt(java.nio.ByteBuffer, int)
	 */
	@Override
	public boolean decrypt(ByteBuffer buf, int size) {
		_loginCrypt.decrypt(buf.array(), buf.position(), size);
		return true;
	}

	/**
	 * @see com.l2jserver.mmocore.interfaces.MMOClient#encrypt(java.nio.ByteBuffer, int)
	 */
	@Override
	public boolean encrypt(ByteBuffer buf, int size) {
		_loginCrypt.encrypt(buf.array(), buf.position(), size);
		buf.position(buf.position() + size);
		return true;
	}
	
	/**
	 * 设置渠道ID
	 * @param channelId
	 */
	public void setChannelId(String channelId) {
		_channelId = channelId;
	}

	/**
	 * 获取渠道ID
	 * @return
	 */
	public String getChannelId() {
		return _channelId;
	}

	/**
	 * 设置客户端的连接状态
	 */
	public LoginClientState getState() {
		return _state;
	}

	/**
	 * 设置客户端状态
	 */
	public void setState(LoginClientState state) {
		_state = state;
	}

	/**
	 * 获得客户端所在的账户
	 */
	public String getAccount() {
		return _account;
	}

	/**
	 * 设置客户端的账户
	 */
	public void setAccount(String account) {
		_account = account;
	}

	/**
	 * 设置客户端的权限等级
	 */
	public void setAccessLevel(int accessLevel) {
		_accessLevel = accessLevel;
	}

	/**
	 * 获得客户端的权限等级
	 */
	public int getAccessLevel() {
		return _accessLevel;
	}

	public void setLastServer(int lastServer) {
		_lastServer = lastServer;
	}

	public int getLastServer() {
		return _lastServer;
	}

	/**
	 * 首次连接的验证key，用来验证从connect状态到Auth状态
	 * @return
	 */
	public int getSessionId() {
		return _sessionId;
	}

	/**
	 * 连游戏服务器的验证key，用来登录游戏服务器时使用的验证
	 */
	public void setSessionKey(int sessionKey) {
		_sessionKey = sessionKey;
	}

	/**
	 * 获取游戏服务器的验证key
	 */
	public int getSessionKey() {
		return _sessionKey;
	}

	public long getConnectionStartTime() {
		return _connectionStartTime;
	}

	public void sendPacket(LoginServerPacket lsp) {
		getConnection().sendPacket(lsp);
	}

	public void close(LoginServerPacket lsp) {
		getConnection().close(lsp);
	}

	@Override
	public void onDisconnection() {
		if (_log.isDebugEnabled()) {
			_log.debug("DISCONNECTED: " + toString());
		}

		if (getState() != LoginClientState.AUTHED_LOGIN) {
			LoginController.getInstance().removeLoginClient(this);
		}
		//-- 不在这里清除LoginController.getInstance().removeAuthedLoginClient(_account),目前的认证机制是先登陆服务器认证，认证通过，客户端断掉连接；接着由游戏服务器认证。若是在此断掉的话则服务端无法作鉴权。
	}

	@Override
	public String toString() {
		InetAddress address = getConnection().getInetAddress();
		if (getState() == LoginClientState.AUTHED_LOGIN) {
			return "[" + getAccount() + " (" + (address == null ? "disconnected" : address.getHostAddress()) + ")]";
		} else {
			return "[" + (address == null ? "disconnected" : address.getHostAddress()) + "]";
		}
	}

	@Override
	protected void onForcedDisconnection() {
		onDisconnection();
	}

	/* (non-Javadoc)
	 * @see labox.innovation.loginserver.Client#getInetAddress()
	 */
	public InetAddress getInetAddress() {
		return getConnection().getInetAddress();
	}
}